1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 import java.math.*;
32 import static java.math.BigDecimal.*;
33
34 public class DivideTests {
35
36
37
38 BigDecimal anotherDivide(BigDecimal dividend, BigDecimal divisor) {
39
40
41
42 if (divisor.signum() == 0) {
43 if (dividend.signum() == 0)
44 throw new ArithmeticException("Division undefined");
45 throw new ArithmeticException("Division by zero");
46 }
47 if (dividend.signum() == 0)
48 return BigDecimal.ZERO;
49 else {
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 BigInteger TWO = BigInteger.valueOf(2);
67 BigInteger FIVE = BigInteger.valueOf(5);
68 BigInteger TEN = BigInteger.valueOf(10);
69
70 BigInteger divisorIntvalue = divisor.scaleByPowerOfTen(divisor.scale()).toBigInteger().abs();
71 BigInteger dividendIntvalue = dividend.scaleByPowerOfTen(dividend.scale()).toBigInteger().abs();
72
73 BigInteger b_prime = divisorIntvalue.divide(dividendIntvalue.gcd(divisorIntvalue));
74
75 boolean goodDivisor = false;
76 int i=0, j=0;
77
78 badDivisor: {
79 while(! b_prime.equals(BigInteger.ONE) ) {
80 int b_primeModTen = b_prime.mod(TEN).intValue() ;
81
82 switch(b_primeModTen) {
83 case 0:
84
85 i++;
86 j++;
87 b_prime = b_prime.divide(TEN);
88 break;
89
90 case 5:
91
92 j++;
93 b_prime = b_prime.divide(FIVE);
94 break;
95
96 case 2:
97 case 4:
98 case 6:
99 case 8:
100
101 i++;
102 b_prime = b_prime.divide(TWO);
103 break;
104
105 default:
106 b_prime = BigInteger.ONE;
107 break badDivisor;
108 }
109 }
110
111 goodDivisor = true;
112 }
113
114 if( ! goodDivisor ) {
115 throw new ArithmeticException("Non terminating decimal expansion");
116 }
117 else {
118
119
120
121
122
123
124
125 MathContext mc = new MathContext(dividend.precision() +
126 (int)Math.ceil(
127 10.0*divisor.precision()/3.0),
128 RoundingMode.UNNECESSARY);
129
130 return dividend.divide(divisor, mc);
131 }
132 }
133 }
134
135 public static int powersOf2and5() {
136 int failures = 0;
137
138 for(int i = 0; i < 6; i++) {
139 int powerOf2 = (int)StrictMath.pow(2.0, i);
140
141 for(int j = 0; j < 6; j++) {
142 int powerOf5 = (int)StrictMath.pow(5.0, j);
143 int product;
144
145 BigDecimal bd;
146
147 try {
148 bd = BigDecimal.ONE.divide(new BigDecimal(product=powerOf2*powerOf5));
149 } catch (ArithmeticException e) {
150 failures++;
151 System.err.println((new BigDecimal(powerOf2)).toString() + " / " +
152 (new BigDecimal(powerOf5)).toString() + " threw an exception.");
153 e.printStackTrace();
154 }
155
156 try {
157 bd = new BigDecimal(powerOf2).divide(new BigDecimal(powerOf5));
158 } catch (ArithmeticException e) {
159 failures++;
160 System.err.println((new BigDecimal(powerOf2)).toString() + " / " +
161 (new BigDecimal(powerOf5)).toString() + " threw an exception.");
162 e.printStackTrace();
163 }
164
165 try {
166 bd = new BigDecimal(powerOf5).divide(new BigDecimal(powerOf2));
167 } catch (ArithmeticException e) {
168 failures++;
169 System.err.println((new BigDecimal(powerOf5)).toString() + " / " +
170 (new BigDecimal(powerOf2)).toString() + " threw an exception.");
171
172 e.printStackTrace();
173 }
174
175 }
176 }
177 return failures;
178 }
179
180 public static int nonTerminating() {
181 int failures = 0;
182 int[] primes = {1, 3, 7, 13, 17};
183
184
185
186
187 for(int i = 0; i < primes.length; i++) {
188 for(int j = i+1; j < primes.length; j++) {
189
190 for(int m = 0; m < primes.length; m++) {
191 for(int n = m+1; n < primes.length; n++) {
192 int dividend = primes[i] * primes[j];
193 int divisor = primes[m] * primes[n];
194
195 if ( ((dividend/divisor) * divisor) != dividend ) {
196 try {
197 BigDecimal quotient = (new BigDecimal(dividend).
198 divide(new BigDecimal(divisor)));
199 failures++;
200 System.err.println("Exact quotient " + quotient.toString() +
201 " returned for non-terminating fraction " +
202 dividend + " / " + divisor + ".");
203 }
204 catch (ArithmeticException e) {
205 ;
206 }
207 }
208
209 }
210 }
211 }
212 }
213
214 return failures;
215 }
216
217 public static int properScaleTests(){
218 int failures = 0;
219
220 BigDecimal[][] testCases = {
221 {new BigDecimal("1"), new BigDecimal("5"), new BigDecimal("2e-1")},
222 {new BigDecimal("1"), new BigDecimal("50e-1"), new BigDecimal("2e-1")},
223 {new BigDecimal("10e-1"), new BigDecimal("5"), new BigDecimal("2e-1")},
224 {new BigDecimal("1"), new BigDecimal("500e-2"), new BigDecimal("2e-1")},
225 {new BigDecimal("100e-2"), new BigDecimal("5"), new BigDecimal("20e-2")},
226 {new BigDecimal("1"), new BigDecimal("32"), new BigDecimal("3125e-5")},
227 {new BigDecimal("1"), new BigDecimal("64"), new BigDecimal("15625e-6")},
228 {new BigDecimal("1.0000000"), new BigDecimal("64"), new BigDecimal("156250e-7")},
229 };
230
231
232 for(BigDecimal[] tc : testCases) {
233 BigDecimal quotient;
234 if (! (quotient = tc[0].divide(tc[1])).equals(tc[2]) ) {
235 failures++;
236 System.err.println("Unexpected quotient from " + tc[0] + " / " + tc[1] +
237 "; expected " + tc[2] + " got " + quotient);
238 }
239 }
240
241 return failures;
242 }
243
244 public static int trailingZeroTests() {
245 int failures = 0;
246
247 MathContext mc = new MathContext(3, RoundingMode.FLOOR);
248 BigDecimal[][] testCases = {
249 {new BigDecimal("19"), new BigDecimal("100"), new BigDecimal("0.19")},
250 {new BigDecimal("21"), new BigDecimal("110"), new BigDecimal("0.190")},
251 };
252
253 for(BigDecimal[] tc : testCases) {
254 BigDecimal quotient;
255 if (! (quotient = tc[0].divide(tc[1], mc)).equals(tc[2]) ) {
256 failures++;
257 System.err.println("Unexpected quotient from " + tc[0] + " / " + tc[1] +
258 "; expected " + tc[2] + " got " + quotient);
259 }
260 }
261
262 return failures;
263 }
264
265 public static int scaledRoundedDivideTests() {
266 int failures = 0;
267
268
269
270
271
272
273
274
275 BigDecimal a = new BigDecimal("31415");
276 BigDecimal a_minus = a.negate();
277 BigDecimal b = new BigDecimal("10000");
278
279 BigDecimal c = new BigDecimal("31425");
280 BigDecimal c_minus = c.negate();
281
282
283 BigDecimal d = new BigDecimal(new BigInteger("-37361671119238118911893939591735"), 10);
284 BigDecimal e = new BigDecimal(new BigInteger("74723342238476237823787879183470"), 15);
285
286 BigDecimal[][] testCases = {
287 {a, b, BigDecimal.valueOf(ROUND_UP, 3), new BigDecimal("3.142")},
288 {a_minus, b, BigDecimal.valueOf(ROUND_UP, 3), new BigDecimal("-3.142")},
289
290 {a, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("3.141")},
291 {a_minus, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("-3.141")},
292
293 {a, b, BigDecimal.valueOf(ROUND_CEILING, 3), new BigDecimal("3.142")},
294 {a_minus, b, BigDecimal.valueOf(ROUND_CEILING, 3), new BigDecimal("-3.141")},
295
296 {a, b, BigDecimal.valueOf(ROUND_FLOOR, 3), new BigDecimal("3.141")},
297 {a_minus, b, BigDecimal.valueOf(ROUND_FLOOR, 3), new BigDecimal("-3.142")},
298
299 {a, b, BigDecimal.valueOf(ROUND_HALF_UP, 3), new BigDecimal("3.142")},
300 {a_minus, b, BigDecimal.valueOf(ROUND_HALF_UP, 3), new BigDecimal("-3.142")},
301
302 {a, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("3.141")},
303 {a_minus, b, BigDecimal.valueOf(ROUND_DOWN, 3), new BigDecimal("-3.141")},
304
305 {a, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},
306 {a_minus, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},
307
308 {c, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},
309 {c_minus, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},
310
311 {d, e, BigDecimal.valueOf(ROUND_HALF_UP, -5), BigDecimal.valueOf(-1, -5)},
312 {d, e, BigDecimal.valueOf(ROUND_HALF_DOWN, -5), BigDecimal.valueOf(0, -5)},
313 {d, e, BigDecimal.valueOf(ROUND_HALF_EVEN, -5), BigDecimal.valueOf(0, -5)},
314 };
315
316 for(BigDecimal tc[] : testCases) {
317 int scale = tc[2].scale();
318 int rm = tc[2].unscaledValue().intValue();
319
320 BigDecimal quotient = tc[0].divide(tc[1], scale, rm);
321 if (!quotient.equals(tc[3])) {
322 failures++;
323 System.err.println("Unexpected quotient from " + tc[0] + " / " + tc[1] +
324 " scale " + scale + " rounding mode " + RoundingMode.valueOf(rm) +
325 "; expected " + tc[3] + " got " + quotient);
326 }
327 }
328
329
330 BigDecimal[][] testCases2 = {
331
332 { new BigDecimal(3090), new BigDecimal(7), new BigDecimal(441) },
333 { new BigDecimal("309000000000000000000000"), new BigDecimal("700000000000000000000"),
334 new BigDecimal(441) },
335 { new BigDecimal("962.430000000000"), new BigDecimal("8346463.460000000000"),
336 new BigDecimal("0.000115309916") },
337 { new BigDecimal("18446744073709551631"), new BigDecimal("4611686018427387909"),
338 new BigDecimal(4) },
339 { new BigDecimal("18446744073709551630"), new BigDecimal("4611686018427387909"),
340 new BigDecimal(4) },
341 { new BigDecimal("23058430092136939523"), new BigDecimal("4611686018427387905"),
342 new BigDecimal(5) },
343 { new BigDecimal("-18446744073709551661"), new BigDecimal("-4611686018427387919"),
344 new BigDecimal(4) },
345 { new BigDecimal("-18446744073709551660"), new BigDecimal("-4611686018427387919"),
346 new BigDecimal(4) },
347 };
348
349 for (BigDecimal test[] : testCases2) {
350 BigDecimal quo = test[0].divide(test[1], RoundingMode.HALF_UP);
351 if (!quo.equals(test[2])) {
352 failures++;
353 System.err.println("Unexpected quotient from " + test[0] + " / " + test[1] +
354 " rounding mode HALF_UP" +
355 "; expected " + test[2] + " got " + quo);
356 }
357 }
358 return failures;
359 }
360
361 public static void main(String argv[]) {
362 int failures = 0;
363
364 failures += powersOf2and5();
365 failures += nonTerminating();
366 failures += properScaleTests();
367 failures += trailingZeroTests();
368 failures += scaledRoundedDivideTests();
369
370 if (failures > 0) {
371 throw new RuntimeException("Incurred " + failures +
372 " failures while testing exact divide.");
373 }
374 }
375 }